/*
 * Copyright (C) 2013 Spreadtrum Communications Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.way.fileexplorer.util;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import android.os.Environment;
import android.util.Log;

public class StorageUtilImpl implements IStorageUtil {

	public static final String TAG = "StorageUtilImpl";

	private final static boolean MMC_SUPPORT = true;
	private static final File EXTERNAL_STORAGE_DIRECTORY;
	private static final File SECONDRARY_STORAGE_DIRECTORY;
	private static final File USB_STORAGE_DIRECTORY;
	private static boolean mIsNAND = false;

	static {
		String path = System.getenv(getMainStoragePathKey());
		EXTERNAL_STORAGE_DIRECTORY = path == null ? Environment
				.getExternalStorageDirectory() : new File(path);
		File internalFile = null;
		try {
			Method method = Environment.class
					.getMethod("getInternalStoragePath");
			Object receiveObject = method.invoke(null);
			if (receiveObject != null && receiveObject instanceof File) {
				internalFile = (File) receiveObject;
			}
		} catch (Exception e) {
			Log.d(TAG, "getMethod failed call getInternalStoragePath method");
		}
		if (internalFile == null) {
			path = System.getenv(getInternalStoragePathKey());
			path = path == null ? "/mnt/internal/" : path;
			internalFile = new File(path);
		}
		SECONDRARY_STORAGE_DIRECTORY = internalFile;
		USB_STORAGE_DIRECTORY = new File("/storage/usbdisk");
	}

	private static String getMainStoragePathKey() {
		// FIXME: Continue highlight at this one on 12b_pxx branch, there is
		// no SECONDARY_STORAGE_TYPE
		// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
		// Log.d(TAG, "version_code = " + Build.VERSION.SDK_INT);
		// return "SECONDARY_STORAGE";
		// }
		try {
			// add a protection to fix if no SECONDARY_STORAGE_TYPE
			if ((null == System.getenv("SECOND_STORAGE_TYPE") || ""
					.equals(System.getenv("SECOND_STORAGE_TYPE").trim()))
					&& MMC_SUPPORT) {
				Log.d(TAG, "No SECOND_STORAGE_TYPE and support emmc");
				return "SECONDARY_STORAGE";
			}
			switch (Integer.parseInt(System.getenv("SECOND_STORAGE_TYPE"))) {
			case 0:
				mIsNAND = true;
				return "EXTERNAL_STORAGE";
			case 1:
				return "EXTERNAL_STORAGE";
			case 2:
				return "SECONDARY_STORAGE";
			default:
				Log.e(TAG,
						"Please check \"SECOND_STORAGE_TYPE\" "
								+ "\'S value after parse to int in System.getenv for framework");
				if (MMC_SUPPORT) {
					return "SECONDARY_SOTRAGE";
				}
				return "EXTERNAL_STORAGE";
			}
		} catch (Exception parseError) {
			Log.e(TAG, "Parsing SECOND_STORAGE_TYPE crashed.\n");
			switch (0) {
			case 0:
				mIsNAND = true;
				return "EXTERNAL_STORAGE";
			case 1:
				return "EXTERNAL_STORAGE";
			case 2:
				return "SECONDARY_STORAGE";
			default:
				if (MMC_SUPPORT) {
					return "SECONDARY_SOTRAGE";
				}
			}
			return "EXTERNAL_STORAGE";
		}
	}

	private static String getInternalStoragePathKey() {
		// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
		// return "EXTERNAL_STORAGE";
		// }
		String keyPath = getMainStoragePathKey();
		if (keyPath != null) {
			return keyPath.equals("EXTERNAL_STORAGE") ? "SECONDARY_STORAGE"
					: "EXTERNAL_STORAGE";
		}
		return "SECONDARY_STORAGE";
	}

	StorageUtilImpl() {
	}

	private final Object sLock = new Object();

	private List<StorageChangedListener> sListeners = new ArrayList<StorageChangedListener>();

	@Override
	public void addStorageChangeListener(StorageChangedListener scl) {
		synchronized (sLock) {
			sListeners.add(scl);
		}
	}

	@Override
	public void removeStorageChangeListener(StorageChangedListener scl) {
		synchronized (sLock) {
			sListeners.remove(scl);
		}
	}

	@Override
	public File getExternalStorage() {
		return EXTERNAL_STORAGE_DIRECTORY;
	}

	@Override
	public File getInternalStorage() {
		return SECONDRARY_STORAGE_DIRECTORY;
	}

	@Override
	public File getUSBStorage() {
		return USB_STORAGE_DIRECTORY;
	}

	@Override
	public boolean getInternalStorageState() {
		/*
		 * SPRD: modify 20131214 Spreadtrum of 249857 Since framework layer's
		 * method "getInternalStorageState" is always return mounted state, the
		 * file manager to adapt to a temporary program that the application
		 * layer's "getInternalStorageState()" always returns true @{
		 */
		// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
		// return true;
		// }
		/* @} */
		try {
			// return
			// "mounted".equals(mMountService.getVolumeState(SECONDRARY_STORAGE_DIRECTORY.getAbsolutePath()));
			return Environment.getExternalStorageState().equals(
					Environment.MEDIA_MOUNTED);
		} catch (Exception rex) {
			return false;
		}
	}

	@Override
	public boolean getUSBStorageState() {
		try {
			// return
			// "mounted".equals(mMountService.getVolumeState(USB_STORAGE_DIRECTORY.getAbsolutePath()));
			return Environment.getExternalStorageState().equals(
					Environment.MEDIA_MOUNTED);
		} catch (Exception rex) {
			return false;
		}
	}

	@Override
	public boolean isInExternalStorage(String path) {
		if (path == null)
			return false;
		return path.startsWith(EXTERNAL_STORAGE_DIRECTORY.getAbsolutePath());
	}

	@Override
	public boolean isInInternalStorage(String path) {
		if (path == null)
			return false;
		return path.startsWith(SECONDRARY_STORAGE_DIRECTORY.getAbsolutePath());
	}

	@Override
	public boolean isInUSBStorage(String path) {
		if (path == null)
			return false;
		return path.startsWith(USB_STORAGE_DIRECTORY.getAbsolutePath());
	}

	@Override
	public void notifyStorageChanged(String path, boolean available) {
		synchronized (sLock) {
			for (StorageChangedListener l : sListeners) {
				l.onStorageChanged(path, available);
			}
		}
	}

	@Override
	public boolean getExternalStorageState() {
		try {
			// return
			// "mounted".equals(mMountService.getVolumeState(EXTERNAL_STORAGE_DIRECTORY.getAbsolutePath()));
			return Environment.getExternalStorageState().equals(
					Environment.MEDIA_MOUNTED);
		} catch (Exception rex) {
			return false;
		}
	}

	@Override
	public boolean isNand() {
		return mIsNAND;
	}

}
